/*
 * Copyright 2012 Finbudget.com
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package finbudgettable.client.ui.grid.cell.datetime;

import com.google.gwt.cell.client.DatePickerCell;
import com.google.gwt.cell.client.ValueUpdater;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.CssResource;
import com.google.gwt.safehtml.client.SafeHtmlTemplates;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import finbudgettable.client.ui.grid.cell.CanBeReadonly;
import finbudgettable.client.ui.grid.cell.HasViewDataCache;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class DateTimeCell extends DatePickerCell implements CanBeReadonly, HasViewDataCache {

    interface Resouces extends ClientBundle {

        interface Style extends CssResource {

            @ClassName("b-datetime-cell__text")
            String bDatetimeCell__text();

            @ClassName("b-datetime-cell")
            String bDatetimeCell();
        }

        @Source("DateTimeCell.css")
        Style style();
    }

    interface Template extends SafeHtmlTemplates {
        @Template("<div class=\"{0}\">{1}</div>")
        SafeHtml date(String className, String date);
    }

    static final DateTimeFormat FORMAT = DateTimeFormat.getFormat(DateTimeFormat.PredefinedFormat.DATE_TIME_SHORT);
    private static final Template TEMPLATE = GWT.create(Template.class);
    static final Resouces RESOUCES = GWT.create(Resouces.class);

    static {
        RESOUCES.style().ensureInjected();
    }

    private boolean readonly;
    private boolean parentReadonly;


    public DateTimeCell() {
        super(FORMAT);
    }

    @Override
    public void render(Context context, Date value, SafeHtmlBuilder sb) {
        // Get the view data.
        Object key = context.getKey();
        Date viewData = getViewData(key);
        if (viewData != null && viewData.equals(value)) {
            clearViewData(key);
            viewData = null;
        }
        String s = null;
        if (viewData != null) {
            s = FORMAT.format(viewData);
        } else if (value != null) {
            s = FORMAT.format(value);
        }
        if (s != null) {
            sb.append(TEMPLATE.date(RESOUCES.style().bDatetimeCell__text(), s));
        }
    }

    @Override
    protected void onEnterKeyDown(Context context, Element parent, Date value, NativeEvent event, ValueUpdater<Date> valueUpdater) {
        if (!isReadonly()) {
            super.onEnterKeyDown(context, parent, value, event, valueUpdater);
        }
    }

    public boolean isReadonly() {
        return readonly || isParentReadonly();
    }

    public void setReadonly(boolean readonly) {
        this.readonly = readonly;
    }

    public boolean isParentReadonly() {
        return parentReadonly;
    }

    public void setParentReadonly(boolean parentReadonly) {
        this.parentReadonly = parentReadonly;
    }

    private final Map<Object, Date> viewDataCache = new HashMap<Object, Date>();

    @Override
    public Date getViewData(Object key) {
        if (key == null) {
            return null;
        }
        return viewDataCache.get(key);
    }

    @Override
    public void clearViewData(Object key) {
        if (key != null) {
            viewDataCache.remove(key);
        }
    }

    @Override
    public void setViewData(Object key, Date viewData) {
        if (key == null) {
            return;
        }
        if (viewData == null) {
            clearViewData(key);
        } else {
            viewDataCache.put(key, viewData);
        }
    }

    /**
     * Clears a cell's viewData cache
     */
    public void clearViewDataCache() {
        viewDataCache.clear();
    }
}
